package com.example.usage.aop.auth;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author jiangzhe
 * @create 2022/9/1 17:57
 */

/**
 * @author sz
 * @DATE 2022/7/30  13:47
 */
@Aspect
@Component
public class WhiteJoinAspect {

    private Map<String, String> roleMap = new HashMap<>();

    {
        roleMap.put("01", "admin");
        roleMap.put("02", "user");
    }

    @Around("@annotation(com.example.usage.aop.auth.NeedWhite)")
    public Object authWhite(ProceedingJoinPoint point) {
        // 1. 获取方法对象
        MethodSignature signature = (MethodSignature) point.getSignature();

        // 2. 获取当前访问用户ID
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        String userID = requestAttributes.getRequest().getParameter("userID");

        // 3. 模拟从数据库中查询用户对应的权限信息
        String currRole = roleMap.get(userID);

        // 4. 获取注解对应属性值
        NeedWhite needWhite = signature.getMethod().getAnnotation(NeedWhite.class);
        String auth = needWhite.auth();

        // 5. 判断当前用户是否有对应的权限
        if (!StringUtils.endsWithIgnoreCase(currRole, auth)) {
            //权限不足  调用认证失败方法
            Object pointTarget = point.getTarget();
            String methodName = needWhite.methodName();
            Class<?> targetClass = pointTarget.getClass();
            Method declaredMethod = null;
            Object result = null;
            try {
                declaredMethod = targetClass.getDeclaredMethod(methodName, null);

                result = declaredMethod.invoke(pointTarget);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }

        Object proceed = null;

        try {
            proceed = point.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        return proceed;
    }
}
